# django-bigip-opspanel (c) Kegan Holtzhausen 2010
# GPlv2 License

from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned

# Pycontrol
import suds
import pycontrol.pycontrol as pyControl

# models
from lbmanager.bigiplite.models import Link, Partition, LoadBalancer

# for details view
from django.http import HttpResponse
import time
import datetime

# reverse lookup
from dns import resolver,reversename

# forms
from django import forms

# defaults
from django.conf import settings


# simple form used for login
class LoginForm(forms.Form):
    username = forms.CharField(max_length=32)
    password = forms.CharField(widget=forms.PasswordInput)

# reverse lookup of IP addresses
def lookup(IP):
	try:
		addr=reversename.from_address(IP)
		return str(resolver.query(addr,"PTR")[0]).rstrip('.')
	except Exception, e:
		return str(IP)

# Set which LB you are using
def setLB(request, loadbalancer):
	try:
		request.session['loadbalancer'] = loadbalancer
	except:
		pass
	return HttpResponseRedirect('../')
	
# Set partition
def setPartition(request):
	try:
		request.session['partition'] = request.POST['partition']
	except:
		pass

# List pools
def listPools(request):
	print "Retrieving pool listings"
	try:
		b = pyControl.BIGIP(
			hostname = request.session['loadbalancer'], 
			username = request.session['username'],
			password = request.session['password'],
			fromurl = True,
			wsdls = ['LocalLB.Pool','Management.Partition']
			)
	except Exception, e:
		print "listPools exception"
		print str(e)

	try:
		part = b.Management.Partition
		part.set_active_partition(active_partition=request.session['partition'])
		return(b.LocalLB.Pool.get_list())
	except:
		return(None)

# List Partitions
def listPartitions(request):
	print "Retrieving partition list"
	try:
		b = pyControl.BIGIP(
			hostname = request.session['loadbalancer'], 
			username = request.session['username'],
			password = request.session['password'],
			fromurl = True,
			wsdls = ['LocalLB.Pool','Management.Partition']
			)
	except Exception, e:
		print "listPartition exception"
		print str(e)
	
	try:
		partitionList = b.Management.Partition.get_partition_list()
		return(partitionList)
	except Exception, e:
		print str(e)
		return(None)
		
# Main INDEX
def index(request):
	try:
		if request.session['loggedIn'] == 1:
			print "User is authenticated as " + str(request.session['username'])
			return render_to_response('index_'+request.session['loadbalancer']+'.html', {'user': request.session['username'], 'partition': request.session['partition'], 'loadbalancer': request.session['loadbalancer']})
	except Exception, e:
		errors = "Bad session or Template for " + str(e) + " Does not exist, please create it"
		pass

	print "fall back index overiding login"
	request.session['loggedIn'] = 1
	request.session['username'] = settings.DEF_USERNAME
	request.session['password'] = settings.DEF_PASSWORD
	request.session['loadbalancer'] = settings.DEF_LOADBALANCER
	request.session['partition'] = settings.DEF_PARTITION
	return render_to_response('index_'+request.session['loadbalancer']+'.html', {'user': request.session['username'], 'partition': request.session['partition'], 'loadbalancer': request.session['loadbalancer'], 'errors': errors})

# Pool Index
def poolIndex(request, partition):
	request.session['partition'] = partition
	pools = listPools(request)
	return render_to_response('poollist.html', {'user': request.session['username'], 'partition': request.session['partition'], 'loadbalancer': request.session['loadbalancer'], 'pools': pools})

# Login Function
def login(request):
	if request.method == 'POST':
		form = LoginForm(request.POST)
		if form.is_valid():
			request.session['loggedIn'] = 1
			request.session['username'] = request.POST['username']
			request.session['password'] = request.POST['password']
			try:
				request.session['loadbalancer']
			except KeyError:
				request.session['loadbalancer'] = 'none'
			try:
				request.session['partition']
			except KeyError:
				request.session['partition'] = 'none'
			return HttpResponseRedirect(request.META['HTTP_REFERER'])
	else:
		form = LoginForm()

	return render_to_response('login.html', { 'form': form })

# Logout nukes your session and index will then re-assert DEFAULTS
def logout(request):
	try:
		del request.session['loggedIn']
		del request.session['username']
		del request.session['loadbalancer']
		del request.session['partition']
	except KeyError:
		pass
	return HttpResponseRedirect('../')
	

def help(request):
	return render_to_response('help.html')


def MemberStatus(request, partition, POOL, **kwargs):
	try:
		if kwargs['template']:
			print "Setting template to " + str(kwargs['template'])
			template = kwargs['template']
		else:
			print "unrecognised template kwarg"
			template = 'complete.html'
	except:
		print "No kwargs, falling back to complete.html"
		template = 'complete.html'
	
	print "Getting pool members for " + str(POOL) + " in partition " + str(partition)
	POOL = POOL.split(',')
	errors = ''
	res = ''

	request.session['partition'] = partition

	try:
		if request.session['loadbalancer'] != 'none':
			print "Found legit looking lb " + str( request.session['loadbalancer'])
		else:
			raise
	except:
		request.session['loadbalancer'] = settings.DEF_LOADBALANCER

	# Fall back to default credentials if user is calling this from a NON-session creating method. like CURL
	try:
		request.session['username']
	except:
		request.session['username'] = settings.DEF_USERNAME
		request.session['password'] = settings.DEF_PASSWORD
		request.session['loadbalancer'] = settings.DEF_LOADBALANCER
	
	try:
		b = pyControl.BIGIP(
			hostname = request.session['loadbalancer'], 
			username = request.session['username'],
			password = request.session['password'],
			fromurl = True,
			wsdls = ['LocalLB.PoolMember','LocalLB.Pool','Management.Partition']
			)
	except Exception, e:
		errors = 'auth failure'
		return render_to_response('complete.html',{'errors': errors, 'output': [], 'partition':request.session['partition'], 'loadbalancer':request.session['loadbalancer'], 'user': request.session['username']})

	part= b.Management.Partition
	part.set_active_partition(active_partition=partition)
	try:
		members = []
		for P in POOL:
			nodes = b.LocalLB.PoolMember.get_session_status(pool_names=[P])
			test = b.LocalLB.PoolMember.get_all_statistics(pool_names=[P])
			idx = 0
			print str(nodes)
			for node in nodes[0]:
				print str(node.member.address)
				monitor = b.LocalLB.PoolMember.get_monitor_status(pool_names = [P])[0][idx].monitor_status
				current_sessions = test[0].statistics[idx].statistics[4].value.low
				print str(monitor)
				members.append([str(P), lookup(node.member.address), str(node.session_status), str(node.member.port),monitor, str(node.member.address), current_sessions, partition])
				idx = idx + 1
	except Exception, e:
		print str(e)

	return render_to_response(template ,{'errors': errors, 'output': members, 'partition':request.session['partition'], 'loadbalancer':request.session['loadbalancer'], 'user': request.session['username']})

	
def MemberStatusWidget(request, partition, POOL):
		request.session['username'] = settings.DEF_USERNAME
		request.session['password'] = settings.DEF_PASSWORD
		request.session['loadbalancer'] = settings.DEF_LOADBALANCER
		return MemberStatus(request, partition, POOL, template='members.html')


def EnableMember(request, partition, POOL, enable_members, disable_members):

	if enable_members == "none":
		print "Settig enable members to none"
		enable_members = None
	if disable_members == "none":
		print "Settig disable members to none"
		disable_members = None

	request.session['partition'] = partition

	try:
		if request.session['loadbalancer'] != 'none':
			print "Found legit looking lb " + str( request.session['loadbalancer'])
		else:
			raise
	except:
		request.session['loadbalancer'] = settings.DEF_LOADBALANCER

	errors = ''

	# Fall back to default credentials if user is calling this from a NON-session creating method. like CURL
	try:
		request.session['username']
	except:
		request.session['username'] = settings.DEF_USERNAME
		request.session['password'] = settings.DEF_PASSWORD
		request.session['loadbalancer'] = settings.DEF_LOADBALANCER

	try:
		b = pyControl.BIGIP(
			hostname = request.session['loadbalancer'], 
			username = request.session['username'],
			password = request.session['password'],
			fromurl = True,
			wsdls = ['LocalLB.PoolMember','LocalLB.Pool','Management.Partition']
			)
	except Exception, e:
		errors = 'auth failure'
		return render_to_response('complete.html',{'errors': errors, 'output': []})

	part= b.Management.Partition
	part.set_active_partition(active_partition=partition)

	try:
		disable_members = disable_members.split(',')
	except Exception, e:
		print "Unable to string split disable_members, possibly its set to none"
		
	try:
		enable_members = enable_members.split(',')
	except Exception, e:
		print "Unable to string split enable_members, possibly its set to none"
		
	print str(disable_members)
	print str(enable_members)
	print str(POOL)

	def member_factory(b, member):
		''' 
		Produces a Common.IPPortDefinition object per member ip:port combination
		object per member ip:port combination. Add these to Common.IPPortDefinitionSequence.

		args: a pycontrol LocalLB.PoolMember object and an ip:port
		combination that you'd like to add.
		'''
		ip,port = member.split(':')
		pmem = b.LocalLB.PoolMember.typefactory.create('Common.IPPortDefinition')
		pmem.address = ip
		pmem.port = int(port)
		return pmem


	def session_state_factory(b, members):
		''' 
		Returns session state objects. Returns a list of session state objects with associated
		members.
		'''
		session_states = []
		monitor_states = []

		# create a type of: 'LocalLB.PoolMember.MemberSessionState'
		# Inside of this type, you'll see that it expects a pool member as an
		# attribute. Let's create that, set our attributes (address, port), and add it to sstate
		# above.
		#MONITOR_STATUS_UNCHECKED 0 Status of an enabled object that is not being monitored.
		#MONITOR_STATUS_CHECKING 1 Initial status of a object until its monitors report.
		#MONITOR_STATUS_UP 2 Status of an enabled object when its monitors succeed.
		#MONITOR_STATUS_DOWN 3 Status of an enabled object when its monitors fail.
		#MONITOR_STATUS_FORCED_DOWN 4 Status of a object when it's forced down manually.
		#MONITOR_STATUS_MAINT 5 Status of an object when in maintenance mode.
		#MONITOR_STATUS_ADDRESS_DOWN 6 Status of an object whose node address monitor fails.
		#MONITOR_STATUS_DOWN_BY_IRULE 7 Status of an object which has been marked down by an iRule.
		#MONITOR_STATUS_DOWN_WAIT_FOR_MANUAL_RESUME 8 Status of an object which has been marked down, and should be manually marked up.
		for x in members:
			sstate = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionState')
			sstate.member = member_factory(b,x) 
			sstate.session_state = 'STATE_DISABLED'
			session_states.append(sstate)
			mstate = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberMonitorState')
			mstate.member = member_factory(b,x) 
			mstate.monitor_state = 'MONITOR_STATUS_FORCED_DOWN'
			monitor_states.append(mstate)
		return session_states, monitor_states


	def disable_member(b, session_objects):
		"""
		Disable our members in the of session state
		objects.
		"""
		try:
			b.LocalLB.PoolMember.set_session_enabled_state(pool_names = [POOL], session_states = [sstate_seq])
			b.LocalLB.PoolMember.set_monitor_state(pool_names = [POOL], monitor_states = [mstate_seq])
		except Exception, e:
			print e
			errors = str(e)
			raise


	def enable_member(b, session_objects):
		"""
		Enable our members in the of session state
		objects.
		"""
		#Note how easy it is to simply 'toggle' the session state now that
		#we are dealing with object attributes.
		for x in sstate_seq.item:
			x.session_state = 'STATE_ENABLED'
		for y in mstate_seq.item:
			y.monitor_state = 'STATE_ENABLED'
		try:
			b.LocalLB.PoolMember.set_session_enabled_state(pool_names = [POOL], session_states = [sstate_seq])
			b.LocalLB.PoolMember.set_monitor_state(pool_names = [POOL], monitor_states = [mstate_seq])
		except Exception, e:
			print e
			errors = str(e)
			raise

	# a members array
	members = []
	print "Setting up Disable sequences"
	if disable_members != None:
		sstate_seq = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionStateSequence')
		mstate_seq = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberMonitorStateSequence')
		print "Populating Sequence items"
		sstate_seq.item, mstate_seq.item = session_state_factory(b, disable_members)
		# Create a list of members.
		print "Creating session and monitor objects"
		session_objects, monitor_objects = session_state_factory(b,disable_members)
		# Disable them.
		print "Disabling members"
		try:
			disable_member(b, session_objects)
		except Exception, e:
			errors = str(e)

		# Let's confirm it's disabled.
		res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])
		print "States: %s" % res
	else:
		print "Skipping none type disable_members"

	print "Setting up Enable sequences"
	if enable_members != None:
		mstate_seq = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberMonitorStateSequence')
		sstate_seq = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionStateSequence')
		sstate_seq.item, mstate_seq.item = session_state_factory(b, enable_members)
		session_objects, monitor_objects = session_state_factory(b, enable_members)
		try:
			enable_member(b, session_objects)
		except Exception, e:
			errors = str(e)
	else:
		print "Skipping none type enable_members"

	res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])
	test = b.LocalLB.PoolMember.get_all_statistics(pool_names=[POOL])

	members = []
	idx=0
	for node in res[0]:
		print str(node.member.address)
		monitor = b.LocalLB.PoolMember.get_monitor_status(pool_names = [POOL])[0][idx].monitor_status
		current_sessions = test[0].statistics[idx].statistics[4].value.low
		members.append([str(POOL), lookup(node.member.address), str(node.session_state),str(node.member.port),monitor,str(node.member.address), current_sessions, partition])
		idx=idx+1
		


	#print "States: %s" % res
	return render_to_response('complete.html',{'errors': errors, 'output': members, 'partition': request.session['partition'], 'loadbalancer': request.session['loadbalancer'], 'user': request.session['username'], 'norefresh': 1})
